{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 硬件安装设置\n",
    "\n",
    "支持安装在:\n",
    "\n",
    "SCOPES:\n",
    "\n",
    "* OPENADC\n",
    "* CWNANO\n",
    "\n",
    "PLATFORMS:\n",
    "\n",
    "* CWLITEARM\n",
    "* CWLITEXMEGA\n",
    "* CWNANO"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "本篇教程将会从软件侧向你介绍ChipWhisperer。它同时会展示如何从ChipWhisperer软件中输入的数据中执行不同的操作。这可以用于你的自建系统，所有的`%%block`标记快可以直接在Jupyter或是你喜欢的命令行环境中运行(注意Jupyper会在区块之间重置路径)。\n",
    "\n",
    "在学习开始之前，你需要先自行了解一些Jupyter基本操作。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CWLITEARM'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What is SimpleSerial"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "SimpleSerial是在ChipWhisperer样例项目中使用的最多的一种通讯协议。它是一种非常基础的串行协议，可以在大部分系统中轻易实现。本系统使用一种标准异步串行协议进行通信，38400波特，8-N-1。\n",
    "\n",
    "所有的信息以ASCII编码发送，且一般使用换行符(`'\\n'`)代表结束。这允许你通过一个标准的终端模拟器与SimpleSerial系统交互。\n",
    "\n",
    "`x`\n",
    "\n",
    "> 发送'x'代表重置缓冲区。这不需要换行符进行终止。建议初始化系统时总是发送一串x以防硬件因为噪音/中断等原因已经处于其他模式。\n",
    "\n",
    "`k00112233445566778899AABBCCDDEEFF\\n`\n",
    "\n",
    "> 加载加密密钥`00112233445566778899AABBCCDDEEFF`至系统中。如果没有调用则系统可能使用默认密钥。\n",
    "\n",
    "`pAABBCCDDEEFF00112233445566778899\\n`\n",
    "\n",
    "> 使用通过'k'命令加载的密钥加密数据`AABBCCDDEEFF00112233445566778899`。系统会返回一行以'r'开始字符串，如下。\n",
    "\n",
    "`rCBBD4A2B34F2571758FF6A797E09859D\\n`\n",
    "\n",
    "> 这是系统的返回内容。如果数据已经被加密了，系统会自动返回这串'r'序列。这意味着上面示例中的加密结果为`cbbd4a2b34f2571758ff6a797e09859d`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构建基础样例"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为了构建基础样例，你需要一个适合你目标机器的编译器。例如ChipWhisperer Lite/Xmega 平台你需要`avr-gcc`以及`avr-libc`。如果你使用的是ARM板子（例如ChipWhisperer Lite/STM32 平台）。你需要适用于ARM驱动的GNU工具链。如果你是其他架构的板子，你需要安装相关的编译器，如果你不确定的话可以运行下列代码块。如果你已经安装了这些内容的话则可以看到编译器版本以及版权信息等。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "#check for avr-gcc\n",
    "avr-gcc --version\n",
    "\n",
    "#check for ARM gcc\n",
    "arm-none-eabi-gcc --version"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在请确保已经安装了相关的工具链，并且可以为你的板子编译硬件。我们将基于simpleserial的新项目，将文件复制到项目目录并构建一个新硬件。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "cd ../../hardware/victims/firmware/\n",
    "mkdir -p simpleserial-base-lab1 && cp -r simpleserial-base/* $_\n",
    "cd simpleserial-base-lab1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接下来我们将进行构建硬件，你需要为你的板子指定`PLATFORM`和`CRYPTO_TARGET`。为了避免在每个区块重复输出这些信息，你可以编辑下面的python代码来定义`PLATFORM`和`CRYPTO_TARGET`。\n",
    "\n",
    "常见的平台为CWLITEXMEGA和CWLITEARM。你也可以通过平台列表来选择`PLATFORM`。\n",
    "\n",
    "本教程不需要使用任何加密，所以我们设置`CRYPTO_TARGET`为`NONE`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "CRYPTO_TARGET = \"NONE\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果你完成了上面的内容，你应该就能成功运行下述代码块了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\" \"$CRYPTO_TARGET\"\n",
    "cd ../../hardware/victims/firmware/simpleserial-base-lab1\n",
    "make PLATFORM=$1 CRYPTO_TARGET=$2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 修改基础样例"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们想修改修改系统，对数据做些处理以便我们可以确认系统已经在工作了。我们使用代码编辑器打开simpleserial-base-lab1文件夹下的`simpleserial-base.c`文件。\n",
    "\n",
    "在文件尾可以找到如下代码块：\n",
    "\n",
    "\n",
    "```C\n",
    "/**********************************\n",
    " * Start user-specific code here. */\n",
    "trigger_high();\n",
    "\n",
    "//16 hex bytes held in 'pt' were sent\n",
    "//from the computer. Store your response\n",
    "//back into 'pt', which will send 16 bytes\n",
    "//back to computer. Can ignore of course if\n",
    "//not needed\n",
    "\n",
    "trigger_low();\n",
    "/* End user-specific code here. *\n",
    "```\n",
    "\n",
    "修改为让它增加数据字节中的每个值：\n",
    "\n",
    "```C\n",
    "/**********************************\n",
    " * Start user-specific code here. */\n",
    "trigger_high();\n",
    "\n",
    "//16 hex bytes held in 'pt' were sent\n",
    "//from the computer. Store your response\n",
    "//back into 'pt', which will send 16 bytes\n",
    "//back to computer. Can ignore of course if\n",
    "//not needed\n",
    "\n",
    "for(int i = 0; i < 16; i++){\n",
    "    pt[i]++;\n",
    "}\n",
    "\n",
    "trigger_low();\n",
    "/* End user-specific code here. *\n",
    " ********************************/\n",
    "```\n",
    "\n",
    "然后使用`make`重新编译："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\" \"$CRYPTO_TARGET\"\n",
    "cd ../hardware/victims/firmware/simpleserial-base-lab1\n",
    "make PLATFORM=$1 CRYPTO_TARGET=$2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python脚本"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最终我们要将硬件上传至板子中并使用python脚本进行交互。不同的平台上传硬件的方式也不一样，对于XMega和STM32平台，你可以使用ChipWhisperer的接口，而其他的你则需要使用额外的程序，如果你有CW1173/Xmega开发板，你可以运行下列代码块无需修改。当运行玩所有代码块石，你将可以看到两个十六进制数，并且第二个值比第一个值更大。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们将开始导入ChipWhiperer模块。它使得我们可以和ChipWhisperer硬件进行通信。ChipWhisperer模块同样包含分析软件，我们会在后续的教程中进行了解。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer as cw"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你可以在[ReadtheDocs](https://chipwhisperer.readthedocs.io/en/latest/api.html)阅读文档或者对模块，自模块，函数调用`help()`获取帮助。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "help(cw)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接下来我们需要需要连接到硬件域（scope）端。从ChipWhisperer 5.1开始，`cw.scope`将会尝试自动检测你的域类型（但你可能会有多个ChipWhisperer链接，你需要指定一个序列号进行连接）。如果你想的话依然可以手动指定域类型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope = cw.scope()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "help(scope)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们同样需要设置目标（进行攻击的目标）的接口。和域设置一样，这里有不同的接口我们可以使用，可以通过`scope.targers.<targer_type>`进行使用。默认使用的SimpleSerial通过UART通信，大部分情况都是正确的选择。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "target = cw.target(scope, cw.targets.SimpleSerial)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接下来，我们会做些基本设置。现在我不无需关系大部分的设置，主要注意`scope.clock`和`scope.io`，设置时钟和串行输入输出总线。\n",
    "\n",
    "**一些目标需要的设置和下列内容不同，请检查相关百科文章找到你的目标设置信息**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# setup scope parameters\n",
    "if SCOPETYPE == \"OPENADC\":\n",
    "    scope.gain.db = 45\n",
    "    scope.adc.samples = 3000\n",
    "    scope.adc.offset = 1250\n",
    "    scope.adc.basic_mode = \"rising_edge\"\n",
    "    scope.clock.clkgen_freq = 7370000\n",
    "    scope.clock.adc_src = \"clkgen_x4\"\n",
    "    scope.trigger.triggers = \"tio4\"\n",
    "    scope.io.tio1 = \"serial_rx\"\n",
    "    scope.io.tio2 = \"serial_tx\"\n",
    "    scope.io.hs2 = \"clkgen\"\n",
    "elif SCOPETYPE == \"CWNANO\":\n",
    "    scope.io.clkout = 7370000\n",
    "    scope.adc.clk_freq = 7370000\n",
    "    scope.io.tio1 = \"serial_rx\"\n",
    "    scope.io.tio2 = \"serial_tx\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "或更简单的使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.default_setup()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在时间和IO总线已经设置完毕，我们便可以对目标进行编程。ChipWhisperer包含一个通用的编程函数，`cw.program_target(scope, type, fw_path)`。这里的`type`是子模块cw.programmers中的一个编程器（`help(cw.programmers)`查看更多信息）。`fw_path`是你要烧入硬件的16进制文件路径。\n",
    "\n",
    "最后部分的二进制文件路径应该和你的系统匹配(CWLITEARM为`<path>/simpleserial-base-CWLITEARM.hex`)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if \"STM\" in PLATFORM or PLATFORM == \"CWLITEARM\" or PLATFORM == \"CWNANO\":\n",
    "    prog = cw.programmers.STM32FProgrammer\n",
    "elif PLATFORM == \"CW303\" or PLATFORM == \"CWLITEXMEGA\":\n",
    "    prog = cw.programmers.XMEGAProgrammer\n",
    "else:\n",
    "    prog = None\n",
    "    \n",
    "fw_path = '../hardware/victims/firmware/simpleserial-base-lab1/simpleserial-base-{}.hex'.format(PLATFORM)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最终对设备进行编程："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cw.program_target(scope, prog, fw_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最后，我们加载一些文本发送至目标，并且读取返回值。我们还在这里进行捕获轨迹，但现在我们不对轨迹进行操作（会在之后的教程中）。你应该可以在接受值中看到原始文本内容。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ktp = cw.ktp.Basic() # object to generate fixed/random key and text (default fixed key, random text)\n",
    "key, text = ktp.next()  # get our fixed key and random text\n",
    "\n",
    "target.simpleserial_write('k', key)\n",
    "target.simpleserial_wait_ack()\n",
    "scope.arm()\n",
    "\n",
    "target.simpleserial_write('p', text)\n",
    "    \n",
    "ret = scope.capture()\n",
    "trace = scope.get_last_trace()\n",
    "output = target.simpleserial_read('r', 16)\n",
    "\n",
    "from binascii import hexlify\n",
    "print(hexlify(output))\n",
    "print(hexlify(text))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "或者也可以运行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ret = cw.capture_trace(scope, target, text, key)\n",
    "if ret:\n",
    "    trace = ret\n",
    "    print(hexlify(ret.textout))\n",
    "    print(hexlify(text))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们完成了这次的教程。我们需要从ChipWhisperer断开。这主要是防止影响之后的会话（最明显是出现`USB can't claim interface`的错误）。不过忘了也别担心，拔去ChipWhisperer连接线再插上会自动修复。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.dis()\n",
    "target.dis()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 未来教程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下一个教程你讲会使用到一些辅助脚本，将会让这些设置更快、更一致。这些脚本运行的设置代码与我们在这里做的基本相同，但如果你想看看它们到底在做什么，它们都包含在`Helper_Scripts`文件夹中。\n",
    "\n",
    "例如，域的设置（时钟，加速等等）都在`Helper Scripts/Setup_Generic.ipynb`中。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.9.12 64-bit",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.9.12"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "aee8b7b246df8f9039afb4144a1f6fd8d2ca17a180786b69acc140d282b71a49"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
